package com.shilupan.panbao.riskmodel.httpclient;

import com.alibaba.fastjson.JSONObject;
import com.shilupan.panbao.riskmodel.constants.CommonConstant;
import com.shilupan.panbao.riskmodel.utils.ObjectUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * 根据请求响应结果以及将响应结果转换Json
 *
 * @author pacey
 */
@Slf4j
public class LocalHttpClient {
    private static int timeout = 720000;

    private static int retryExecutionCount = 5;

    protected static CloseableHttpClient httpClient = HttpClientFactory
            .createHttpClient(150, 20, timeout, retryExecutionCount);

    /**
     * @param timeout 时长
     */
    public static void setTimeout(int timeout) {
        LocalHttpClient.timeout = timeout;
    }

    /**
     * 设置参数
     *
     * @param retryExecutionCount 重连次数
     */
    public static void setRetryExecutionCount(int retryExecutionCount) {
        LocalHttpClient.retryExecutionCount = retryExecutionCount;
    }

    /**
     * 初始化
     *
     * @param maxTotal    最大连接数
     * @param maxPerRoute 路由最大连接数
     */
    public static void init(int maxTotal, int maxPerRoute) {
        try {
            httpClient.close();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        httpClient = HttpClientFactory.createHttpClient(maxTotal,
                maxPerRoute,
                timeout,
                retryExecutionCount);
    }


    /**
     * 根据 请求返回 response 响应
     *
     * @param request
     * @return
     */
    public static CloseableHttpResponse execute(HttpGet request) {
        logRequest(request);
        try {
            return httpClient.execute(request, HttpClientContext.create());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 根据 请求返回 response 响应
     *
     * @param request
     * @return
     */
    public static CloseableHttpResponse execute(HttpUriRequest request) {
        logRequest(request);
        try {
            return httpClient.execute(request, HttpClientContext.create());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 自动解析Json对象时执行的http请求 (用于 executeJsonResult 方法调用)
     *
     * @param request
     * @param responseHandler
     * @param <T>
     * @return
     */
    public static <T> T execute(HttpUriRequest request, ResponseHandler<T> responseHandler) {
        String uriId = logRequest(request);
        if (responseHandler instanceof LocalResponseHandler) {
            LocalResponseHandler lrh = (LocalResponseHandler) responseHandler;
            lrh.setUriId(uriId);
        }
        try {
            return httpClient.execute(request, responseHandler, HttpClientContext.create());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 自动解析Json对象时执行的http请求 (用于 executeJsonResult 方法调用)
     *
     * @param request
     * @return
     */
    public static JSONObject executeForJson(HttpUriRequest request) {
        return execute(request,JSONObject.class);
    }
    public static<T> T execute(HttpUriRequest request, Class<T> clazz) {
        return execute(request,JsonResponseHandler.createResponseHandler(clazz));
    }

    /**
     *
     * @param url 地址
     * @param jsonStringParams Json参数
     * @param clazz 返回类型
     * @return
     */
    public static <T>T executePost(String url,String jsonStringParams,Class<T> clazz) {
        RequestBuilder requestBuilder = RequestBuilder
                .post()
                .setCharset(Charset.forName(CommonConstant.CHARSET_UTF))
                .setHeader("Content-Type", CommonConstant.CONTENT_TYPE_JSON)
                .setHeader("accept", CommonConstant.CONTENT_TYPE_JSON)
                .setEntity(new StringEntity(jsonStringParams,
                        CommonConstant.CHARSET_UTF))
                .setUri(url);
        HttpUriRequest request = requestBuilder.build();
        return execute(request, JsonResponseHandler.createResponseHandler(clazz));
    }

    /**
     *  post请求返回Json
     * @param url 请求地址
     * @param jsonStringParams 请求参数Str
     * @return
     */
    public static JSONObject executePostJson(String url, String jsonStringParams){
        return executePost(url,jsonStringParams,JSONObject.class);
    }

    /**
     * 数据返回自动转为Json
     *
     * @param request qo
     * @return result
     */
    public static JSONObject executeJsonResult(HttpUriRequest request) {
        return execute(request, JsonResponseHandler.createResponseHandler(JSONObject.class));
    }

    /**
     * 数据返回自动JSON对象解析
     *
     * @param request qo
     * @param clazz   clazz
     * @return result
     */
    public static <T> T executeJsonResult(HttpUriRequest request, Class<T> clazz) {
        return execute(request, JsonResponseHandler.createResponseHandler(clazz));
    }

    /**
     * post获取String结果
     * @param url
     * @param params
     * @return
     */
    public static String post(String url,String params){
        // 设置HttpClient请求信息
        RequestBuilder requestBuilder = RequestBuilder
                .post()
                .setCharset(Charset.forName(CommonConstant.CHARSET_UTF))
                .setHeader("Content-type", CommonConstant.PLAIN_TEXT_TYPE)
                .setEntity(new StringEntity(params,CommonConstant.CHARSET_UTF))
                .setUri(url);
        HttpUriRequest httpUriRequest = requestBuilder.build();
        CloseableHttpResponse responseDataEnc =execute(httpUriRequest);

        if(!ObjectUtils.isObjectEmpty(responseDataEnc)){
            // 初始化: 解密结果
            int status = responseDataEnc.getStatusLine().getStatusCode();
            if (status >= 200 && status < 300) {
                HttpEntity entity = responseDataEnc.getEntity();
                try {
                    return EntityUtils.toString(entity, "utf-8");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }else if ((status >= 400 && status < 405) || status == 413){
                log.info("Unexpected response status: " + status);
            }
        }
        return null;
    }

    /**
     * 日志记录（解析时用）
     *
     * @param request qo
     * @return log qo id
     */
    private static String logRequest(HttpUriRequest request) {
        String id = UUID.randomUUID().toString();
        if (log.isInfoEnabled() || log.isDebugEnabled()) {
            if (request instanceof HttpEntityEnclosingRequestBase) {
                HttpEntityEnclosingRequestBase request_base = (HttpEntityEnclosingRequestBase) request;
                HttpEntity entity = request_base.getEntity();
                String content = null;
                //MULTIPART_FORM_DATA 请求类型判断
                if (entity.getContentType().toString()
                        .indexOf(ContentType.MULTIPART_FORM_DATA.getMimeType()) == -1) {
                    try {
                        content = EntityUtils.toString(entity);
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                    }
                }
                try {
                    log.info("URI[{}] {} {} ContentLength:{} Content:{}",
                            id,
                            request.getURI().toString(),
                            entity.getContentType(),
                            entity.getContentLength(),
                            entity.getContentLength()<2048?EntityUtils.toString(entity):entity.getContentLength()
                            );
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                log.info("URI[{}] {}", id, request.getURI().toString());
            }
        }
        return id;
    }

    /**
     * 获得服务器端数据，以InputStream形式返回
     *
     * @return
     * @throws IOException
     */
    public static InputStream getInputStream(String urlPath ) {
        InputStream inputStream = null;
        HttpURLConnection httpURLConnection = null;
        try {
            URL url = new URL(urlPath);
            if (url != null) {
                httpURLConnection = (HttpURLConnection) url.openConnection();
                // 设置连接网络的超时时间
                httpURLConnection.setConnectTimeout(3000);
                httpURLConnection.setDoInput(true);
                // 设置本次http请求使用get方式请求
                httpURLConnection.setRequestMethod("GET");
                int responseCode = httpURLConnection.getResponseCode();
                if (responseCode == 200) {
                    // 从服务器获得一个输入流
                    inputStream = httpURLConnection.getInputStream();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return inputStream;
    }

    /**
     *  1、post
     *  2、form表单提交
     *  3、返回值为String
     * @param url
     * @param map
     * @return
     */
    public static <T> T postForm(String url,Map<String, String> map,Class<T> clazz) {
        // 设置HttpClient请求信息
        HttpUriRequest requestBuilder = RequestBuilder
                .post()
                .setCharset(Charset.forName(CommonConstant.CHARSET_UTF))
                .setEntity(buildForm(map))
                .setUri(url)
                .build();

       return execute(requestBuilder,JsonResponseHandler.createResponseHandler(clazz));

    }

    /**
     * 返回JSON结果
     * @param url
     * @param map
     * @return
     */
    public static JSONObject postFormJsonResult(String url, Map<String, String> map) {
        return postForm(url,map, JSONObject.class);
    }

    /**
     * get请求
     * @param url 请求地址
     * @param params 参数
     * @param clazz 返回类型
     * @return
     */
    public static <T>T get(String url,Map<String,String> params,Class<T> clazz){
        // 设置HttpClient请求信息
        HttpUriRequest requestBuilder = RequestBuilder
                .get()
                .setCharset(Charset.forName(CommonConstant.CHARSET_UTF))
                .setEntity(buildForm(params))
                .setUri(url)
                .build();
        return execute(requestBuilder,JsonResponseHandler.createResponseHandler(clazz));
    }

    public static JSONObject get(String url, Map<String,String> map){
        return get(url,map,JSONObject.class);
    }

    public static JSONObject get(String url){
        return get(url,null);
    }


    /**
     * 构建form参数
     * @param paramMap
     * @return
     */
    private static HttpEntity buildForm(Map<String,String> paramMap){
        if(paramMap == null){
            log.info("未传入请求参数");
            return null;
        }
        List<NameValuePair> formparams = new ArrayList<>();
        for (Map.Entry<String, String> entry : paramMap.entrySet()) {
            formparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
        }

        HttpEntity reqEntity = null;
        try {
            reqEntity = new UrlEncodedFormEntity(formparams, CommonConstant.CHARSET_UTF);
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage());
        }

        return reqEntity;
    }

}

